package be.ipl.pigolo.domaine;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Date;
import java.util.GregorianCalendar;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import javax.validation.constraints.Min;

import be.ipl.pigolo.domaine.DeValeur.Couleur;
import be.ipl.pigolo.util.GestionFichier;
import be.ipl.pigolo.util.GestionFichierImpl;
import be.ipl.pigolo.util.Util;

import com.sun.istack.internal.NotNull;
import com.sun.istack.internal.Nullable;

@Entity
@Table(name = "PARTIES", schema = "PIGOLO")
public class Partie implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 6821606712113755840L;

	/**
	 * 
	 */

	public static final int NB_DES = 10;

	@Transient
	private GestionFichier fichier;

	@Id
	@GeneratedValue(strategy = GenerationType.IDENTITY)
	private int id;

	@NotNull
	@Column(unique = true)
	private String nom;

	private String desDB;

	private String cochonStringList;

	@NotNull
	@Enumerated(EnumType.STRING)
	private Etat etat = Etat.EN_ATTENTE;

	@Transient
	private List<De> listeDes;
	@Transient
	private Cochon[][] tableauDesCochons;
	@Transient
	private De deOrdre;
	@Transient
	private static DeValeur.Couleur couleurAChoisir;
	@Transient
	private static int sommeDeRouge = 0;

	@Transient
	private static int sommeDeBlanc = 0;

	@Transient
	private static int sommeDeVert = 0;

	@NotNull
	private int nbParticipants;
	@NotNull
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar dateDebut;
	@Nullable
	@Temporal(TemporalType.TIMESTAMP)
	private Calendar dateFin;

	/**
	 * Timer entre 2 tours permettant aux joueurs de lire les messages
	 */
	@Transient
	private int timerEntreTour = 5;

	/**
	 * Timer pendant un tour permettant aux joueurs de prendre un cochon
	 */
	@Min(0)
	private int timerTour = 10;

	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER)
	@JoinColumn(name = "PARTIE_ID")
	private List<PartieFermier> fermiers = new ArrayList<PartieFermier>();

	public enum Etat {
		EN_ATTENTE {
			boolean ajouterFermier(PartieFermier monFermier, final Partie partie) {
				if (partie.getNbParticipants() == 0) {
					partie.fichier = new GestionFichierImpl(partie.getId());
					if (!partie.fichier.estVide()) {
						partie.fichier.RAZ();
					}
				}

				if (partie.getNbParticipants() >= 4) {
					return false;
				}
				String nom = monFermier.getFermier().getNom();
				if (partie.getFermier(nom) != null)
					return false;
				partie.fermiers.add(monFermier);
				partie.nbParticipants++;
				return true;
			}

			boolean commencerPartie(Partie partie) {
				for (PartieFermier pf : partie.getFermiers()) {
					pf.getFermier().setStatusJeu(Fermier.STATUS_JEU.ENJEU);
				}
				partie.fichier = new GestionFichierImpl(partie.getId());
				partie.fichier.inscrireUneLigne("Nom de la partie :"
						+ partie.getNom());
				partie.dateDebut = new GregorianCalendar();
				DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
				java.util.Date dateDate = partie.dateDebut.getTime();
				String retour = dateFormat.format(dateDate);
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
				;
				String heure = sdf.format(new Date());
				partie.fichier.inscrireUneLigne("Début de la partie : "
						+ retour + " " + heure);
				partie.etat = EN_COURS;
				String adversaires = "Adversaires :";
				for (PartieFermier pf : partie.getFermiers()) {
					adversaires += " " + pf.getFermier().getNom() + " et";
				}
				adversaires.substring(adversaires.length() - 4,
						adversaires.length());
				partie.fichier.inscrireUneLigne(adversaires);
				partie.fichier.inscrireUneLigne("");
				return true;
			}

			boolean annuler(Partie partie) {
				partie.etat = ANNULEE;
				for (PartieFermier pf : partie.getFermiers()) {
					pf.getFermier().setStatusJeu(Fermier.STATUS_JEU.HORSJEU);
				}
				// partie.getFermiers().clear(); // TODO manque surement une
				// étape
				return true;
			}
		},
		EN_COURS {
			boolean commencerTourSuivant(Partie partie) {

				int nbJoureursRestant = partie.getNbParticipants();
				for (PartieFermier pf : partie.getFermiers()) {
					if (pf.getFermier().getStatutJeu() == Fermier.STATUS_JEU.OBSERVATEUR) {
						nbJoureursRestant--;
					}
					if (pf.getFermier().getStatutConnexion() == Fermier.STATUS_CONNEXION.DECONNECTE) {
						partie.finDePartie();
						return false;
					}
				}

				if (nbJoureursRestant <= 1) {
					// On termine la partie
					partie.finDePartie();
					return false;
				}

				// Initialisation de la couleur à choisir (par défaut le gris)
				couleurAChoisir = null;

				partie.nouveauLancer();

				String val = partie.deOrdre.convertirValeur();
				if (val.equals(DeOrdre.Action.PLUS_GRANDE_SOMME.name())) {

					calculSomme(partie);

					int max = Math.max(sommeDeBlanc,
							Math.max(sommeDeRouge, sommeDeVert));
					int nbMax = 0; // Nombre de valeurs maximales
					if (max == sommeDeRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMax++;
					}
					if (max == sommeDeBlanc) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMax++;
					}
					if (max == sommeDeVert) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMax++;
					}
					// Si plusieurs max => Gris
					if (nbMax != 1) {
						couleurAChoisir = null;
					}
				}
				if (val.equals(DeOrdre.Action.PLUS_PETITE_SOMME.name())) {
					int min = Math.min(sommeDeBlanc,
							Math.min(sommeDeRouge, sommeDeVert));
					int nbMin = 0; // Nombre de valeurs minimales

					if (min == sommeDeRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMin++;
					}
					if (min == sommeDeBlanc) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMin++;
					}
					if (min == sommeDeVert) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMin++;
					}
					// Si plusieurs min => Gris
					if (nbMin != 1) {
						couleurAChoisir = null;
					}
				}
				if (val.equals(DeOrdre.Action.PLUS_GRAND_ECART.name())) {
					// Calculs des écart
					int maxRouge = Integer.MIN_VALUE, maxBlanc = Integer.MIN_VALUE, maxVert = Integer.MIN_VALUE;
					int minRouge = Integer.MAX_VALUE, minBlanc = Integer.MAX_VALUE, minVert = Integer.MAX_VALUE;
					for (De d : partie.listeDes) {
						if (((DeValeur) d).getCouleur() == Couleur.ROUGE) {
							minRouge = Math.min(minRouge, d.getValeur());
							maxRouge = Math.max(maxRouge, d.getValeur());
						}
						if (((DeValeur) d).getCouleur() == Couleur.BLANC) {
							minBlanc = Math.min(minBlanc, d.getValeur());
							maxBlanc = Math.max(maxBlanc, d.getValeur());
						} else {
							minVert = Math.min(minVert, d.getValeur());
							maxVert = Math.max(maxVert, d.getValeur());
						}
					}
					int ecartRouge = maxRouge - minRouge;
					int ecartBlanc = maxBlanc - minBlanc;
					int ecartVert = maxVert - minVert;

					int maxEcart = Math.max(ecartRouge,
							Math.max(ecartVert, ecartBlanc));

					int nbMaxEcart = 0; // Nombre de couleurs ayant l'écart
										// maximal

					if (maxEcart == ecartRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMaxEcart++;
					}
					if (maxEcart == ecartBlanc) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMaxEcart++;
					}
					if (maxEcart == ecartVert) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMaxEcart++;
					}
					// Si plusieurs écart maximaux => Gris
					if (nbMaxEcart != 1) {
						couleurAChoisir = null;
					}
				}
				if (val.equals(DeOrdre.Action.PLUS_GRAND_NOMBRE_IMPAIR.name())) {
					int nbRouge = 0, nbBlanc = 0, nbVert = 0;
					for (De d : partie.listeDes) {
						// Si la valeur du dé est impaire
						if (d.getValeur() % 2 == 1) {
							if (((DeValeur) d).getCouleur() == Couleur.ROUGE) {
								nbRouge++;
							}
							if (((DeValeur) d).getCouleur() == Couleur.BLANC) {
								nbBlanc++;
							} else {
								nbVert++;
							}
						}
					}

					int max = Math.max(nbRouge, Math.max(nbVert, nbBlanc));

					int nbMax = 0; // Nombre de max

					if (max == nbRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMax++;
					}
					if (max == nbVert) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMax++;
					}
					if (max == nbBlanc) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMax++;
					}
					// Si plusieurs max => Gris
					if (nbMax != 1) {
						couleurAChoisir = null;
					}
				}
				if (val.equals(DeOrdre.Action.PLUS_HAUTE_VALEUR.name())) {
					int maxRouge = Integer.MIN_VALUE, maxBlanc = Integer.MIN_VALUE, maxVert = Integer.MIN_VALUE;
					for (De d : partie.listeDes) {
						if (((DeValeur) d).getCouleur() == Couleur.ROUGE) {
							maxRouge = Math.max(maxRouge, d.getValeur());
						}
						if (((DeValeur) d).getCouleur() == Couleur.BLANC) {
							maxBlanc = Math.max(maxBlanc, d.getValeur());
						} else {
							maxVert = Math.max(maxVert, d.getValeur());
						}
					}

					int max = Math.max(maxRouge, Math.max(maxVert, maxBlanc));

					int nbMax = 0; // Nombre de max

					if (max == maxRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMax++;
					}
					if (max == maxBlanc) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMax++;
					}
					if (max == maxVert) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMax++;
					}
					// Si plusieurs maximaux => Gris
					if (nbMax != 1) {
						couleurAChoisir = null;
					}
				}
				if (val.equals(DeOrdre.Action.SOMME_EGALE_A_9.name())) {
					calculSomme(partie);

					int ecartBlanc = Math.abs(sommeDeBlanc - 9);
					int ecartRouge = Math.abs(sommeDeRouge - 9);
					int ecartVert = Math.abs(sommeDeVert - 9);

					int minEcart = Math.max(ecartBlanc,
							Math.max(ecartRouge, ecartVert));

					int nbMinEcart = 0; // Nombre de sommes plus proches de 9
					if (minEcart == ecartRouge) {
						couleurAChoisir = DeValeur.Couleur.ROUGE;
						nbMinEcart++;
					}
					if (minEcart == ecartBlanc) {
						couleurAChoisir = DeValeur.Couleur.BLANC;
						nbMinEcart++;
					}
					if (minEcart == ecartVert) {
						couleurAChoisir = DeValeur.Couleur.VERT;
						nbMinEcart++;
					}
					// Si plusieurs sommes plus proches de 9 => Gris
					if (nbMinEcart != 1) {
						couleurAChoisir = null;
					}
				}

				partie.initialiserCochons();
				return true;
			}

			public boolean terminerPartie(Partie partie) {
				for (PartieFermier pf : partie.getFermiers()) {
					pf.getFermier().setStatusJeu(Fermier.STATUS_JEU.HORSJEU);
				}
				partie.dateFin = new GregorianCalendar();
				DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy");
				java.util.Date dateDate = partie.dateFin.getTime();
				String retour = dateFormat.format(dateDate);
				SimpleDateFormat sdf = new SimpleDateFormat("HH:mm");
				;
				String heure = sdf.format(new Date());
				partie.fichier = new GestionFichierImpl(partie.getId());
				partie.fichier.inscrireUneLigne("Fin de la partie : " + retour
						+ " " + heure);

				int cptTestNbrJoueursAvecPurins = 0;
				for (PartieFermier pf : partie.getFermiers()) {

					if (pf.getPurins() != 0)
						cptTestNbrJoueursAvecPurins++;
					if (cptTestNbrJoueursAvecPurins >= 2)
						break;
				}

				if (cptTestNbrJoueursAvecPurins > 1)
					partie.etat = INTERROMPUE;
				else
					partie.etat = TERMINEE;
				return true;

			}

		},
		TERMINEE {
			PartieFermier estVainqueur(Partie partie) {
				List<PartieFermier> partieFermier = partie.getFermiers();
				for (PartieFermier pf : partieFermier) {
					if (pf.getPurins() > 0) {
						return pf;
					}
				}
				return null;
			}
		},

		ANNULEE {

		},

		INTERROMPUE {
		// Pas à gérer
		};

		/**
		 * Ajoute un fermier à la partie
		 * 
		 * @param fermier
		 *            Le fermier à ajouter
		 * @param partie
		 *            La partie qui doit accueillir un nouveau fermier
		 * @return True si le fermier a pu être ajouté, false sinon
		 */
		boolean ajouterFermier(PartieFermier fermier, Partie partie) {
			return false;
		}

		/**
		 * Méthode qui calcule la somme de chaque couleurs de dés
		 * 
		 * @param partie
		 *            Partie liée aux dés lancés
		 */
		protected void calculSomme(Partie partie) {
			for (De d : partie.listeDes) {
				if (((DeValeur) d).getCouleur() == Couleur.ROUGE) {
					sommeDeRouge += d.getValeur();
				}
				if (((DeValeur) d).getCouleur() == Couleur.BLANC) {
					sommeDeBlanc += d.getValeur();
				} else {
					sommeDeVert += d.getValeur();
				}
			}
		}

		/**
		 * Commence la partie
		 * 
		 * @param partie
		 *            La partie à commencer
		 * @return True si la partie a pû commencer, false sinon
		 */
		boolean commencerPartie(Partie partie) {
			return false;
		}

		/**
		 * Annuler une partie
		 * 
		 * @param partie
		 *            La partie à annuler
		 * @return True si la partie a pû être annulée, false sinon
		 */
		boolean annuler(Partie partie) {
			return false;
		}

		/**
		 * Commence le tour suivant
		 * 
		 * @param partie
		 *            Partie dont le tour suivant doit commencer
		 * @return True si le tour suivant a pû commencer
		 */
		boolean commencerTourSuivant(Partie partie) {
			return false;
		}

		/**
		 * Termine partie
		 * 
		 * @param partie
		 *            Partie à terminer
		 * @return True si la prtie a pû être terminée, false sinon
		 */
		public boolean terminerPartie(Partie partie) {
			return false;
		}

		/**
		 * Détermine le vainqueur
		 * 
		 * @param partie
		 *            dont on désire connaitre le vainqueur
		 * @return Le vainqueur si la partie est terminée, null sinon
		 */
		PartieFermier estVainqueur(Partie partie) {
			return null;
		}

	}

	/**
	 * Constructeur par défaut utile pour EJB
	 */
	protected Partie() {
	}

	/**
	 * Constructeur de la partie
	 * 
	 * @param nom
	 *            Nom de la partie
	 */
	public Partie(String nom) {
		this.nbParticipants = 0;
		this.nom = nom;
		this.cochonStringList = "";// TODO MODIFS A INSERE
		this.desDB = "";
	}

	/**
	 * Constructeur de la partie
	 * 
	 * @param nom
	 *            Nom de la partie
	 * @param timer
	 *            Temps entre chaque tour
	 */
	public Partie(String nom, int timer) {
		this(nom);
		this.timerTour = timer;
	}

	/**
	 * Renvoie l'id de la partie
	 * 
	 * @return L'id de la partie
	 */
	public int getId() {
		return id;
	}

	/**
	 * Renvoie le nom de la partie
	 * 
	 * @return Le nom de la partie
	 */
	public String getNom() {
		return nom;
	}

	/**
	 * Renvoie l'état de la partie
	 * 
	 * @return l'état de la partie
	 */
	public Etat getEtat() {
		return etat;
	}

	/**
	 * Renvoie la liste des dés valeurs
	 * 
	 * @return la liste des dés valeurs
	 */
	public List<De> getDeValeurs() {

		List<De> listDe = new ArrayList<De>();

		if (desDB.length() == 0)
			return null;
		for (int i = 0; i < 13; i += 6) {
			DeValeur deValB = new DeValeur(
					be.ipl.pigolo.domaine.DeValeur.Couleur.BLANC);
			DeValeur deValR = new DeValeur(
					be.ipl.pigolo.domaine.DeValeur.Couleur.ROUGE);
			DeValeur deValV = new DeValeur(
					be.ipl.pigolo.domaine.DeValeur.Couleur.VERT);
			deValV.setValeur((int) desDB.charAt(i) - 48);
			deValB.setValeur((int) desDB.charAt(i + 2) - 48);
			deValR.setValeur((int) desDB.charAt(i + 4) - 48);
			listDe.add(deValV);
			listDe.add(deValB);
			listDe.add(deValR);
		}

		return listDe;
	}

	/**
	 * renvoie le dé ordre
	 * 
	 * @return le dé ordre
	 */
	public De getDeOrdre() {
		if (desDB.length() == 0)
			return null;
		String de = desDB.substring(desDB.length() - 1, desDB.length());
		DeOrdre deOrdre = new DeOrdre();
		deOrdre.setValeur(Integer.parseInt(de));
		return deOrdre;
	}

	/**
	 * renvoie la liste des fermiers dans l'ordre alphabétique
	 * 
	 * @return la liste des fermiers dans l'ordre alphabétique
	 */
	public List<PartieFermier> getFermiers() {
		List<PartieFermier> partieFermier = new ArrayList<PartieFermier>(
				fermiers);
		Collections.sort(partieFermier,
				new PartieFermier.PartieFermierComparator());
		return fermiers;
	}

	/**
	 * Renvoi le fermier via son nom s'il s'y trouve
	 * 
	 * @param nom
	 *            Le nom du fermier
	 * @return le fermier dont le nom est en parametre ; null s'il ne le trouve
	 *         pas
	 */
	public PartieFermier getFermier(String nom) {
		for (PartieFermier partieFermier : fermiers)
			if (partieFermier.getFermier().getNom().equals(nom))
				return partieFermier;
		return null;
	}

	/**
	 * Insert le tableau des cochons dans le champs de sauvegarde
	 * 
	 * @return return false si les informations sont manquantes ou null
	 */
	private boolean updateCochonStringList() {
		String tempCochonString = "";
		if (tableauDesCochons == null)
			return false;
		for (int i = 0; i < tableauDesCochons.length; i++) {
			if (i > 0)
				tempCochonString += "@";
			for (int j = 0; j < tableauDesCochons[i].length; j++) {
				if (tableauDesCochons[i][j] != null) {
					if (j > 0)
						tempCochonString += "#";
					tempCochonString += tableauDesCochons[i][j].getId() + ","
							+ tableauDesCochons[i][j].getX() + ","
							+ tableauDesCochons[i][j].getY() + ","
							+ tableauDesCochons[i][j].getCouleurName() + ","
							+ tableauDesCochons[i][j].getEtat().name();
				}
			}
		}
		cochonStringList = tempCochonString;
		return true;
	}

	/**
	 * Insert le tableau des dés dans le champs de sauvegarde
	 * 
	 * @return return false si les informations sont manquantes ou null
	 * 
	 */
	private boolean updateDeStringList() {
		String tempDe = "";
		if (listeDes == null)
			return false;
		for (De d : listeDes) {
			tempDe += d.getValeur() + "-";
		}
		if (deOrdre == null)
			return false;
		tempDe += deOrdre.getValeur();
		desDB = tempDe;
		return true;
	}

	/**
	 * Renvoie la table des cochons
	 * 
	 * @return la table des cochons
	 */
	public Cochon[][] getTableauDesCochons() {
		if (cochonStringList.length() == 0)
			return null;
		String listeCochons[] = cochonStringList.split("@");
		tableauDesCochons = new Cochon[5][5]; // remise à zéro du tableau
		for (int i = 0; i < listeCochons.length; i++) {
			if (listeCochons[i].length() > 0) {
				String subListeCochons[] = listeCochons[i].split("#");
				for (int j = 0; j < subListeCochons.length; j++) {
					if (subListeCochons[j].length() > 0) {

						String cochonStr[] = subListeCochons[j].split(",");

						if (cochonStr.length > 0) {

							Cochon coco = new Cochon(
									Integer.parseInt(cochonStr[0]),
									Integer.parseInt(cochonStr[1]),
									Integer.parseInt(cochonStr[2]),
									be.ipl.pigolo.domaine.Cochon.Couleur
											.valueOf(cochonStr[3]),
									be.ipl.pigolo.domaine.Cochon.Etat
											.valueOf(cochonStr[4]));
							if (coco.getEtat() == be.ipl.pigolo.domaine.Cochon.Etat.NON_RAMASSER)
								tableauDesCochons[coco.getY()][coco.getX()] = coco;
						}
					}
				}
			}
		}
		return tableauDesCochons;
	}

	/**
	 * Renvoie le nombre de participants
	 * 
	 * @return le nombre de fermiers de la partie courante
	 */
	public int getNbParticipants() {
		return nbParticipants;
	}

	/**
	 * Renvoie le timer entre 2 tours
	 * 
	 * @return le timer entre 2 tours
	 */
	public int getTimerEntreTour() {
		return timerEntreTour;
	}

	/**
	 * Renvoie le timer d'un tour
	 * 
	 * @return Le timer d'un tour
	 */
	public int getTimerTour() {
		return timerTour;
	}

	/**
	 * 
	 * @return la string des dés
	 */
	public String getDesDB() {
		return desDB;
	}

	/**
	 * Cette méthode permet d'initialiser les cochons en fonction du nombre de
	 * fermiers.
	 */
	public void initialiserCochons() {
		int maxCochons = 3;
		if (this.getNbParticipants() == 2) {
			maxCochons = 1;
		} else if (this.getNbParticipants() == 3) {
			maxCochons = 2;
		}
		tableauDesCochons = new Cochon[5][5];
		for (int i = 0; i < 1 * maxCochons; i++) {
			placerCochon(new Cochon(i + 1, Cochon.Couleur.ROUGE,
					Cochon.Etat.NON_RAMASSER));
		}
		for (int i = 1 * maxCochons; i < 2 * maxCochons; i++) {
			placerCochon(new Cochon(i + 1, Cochon.Couleur.BLANC,
					Cochon.Etat.NON_RAMASSER));
		}
		for (int i = 2 * maxCochons; i < 3 * maxCochons; i++) {
			placerCochon(new Cochon(i + 1, Cochon.Couleur.VERT,
					Cochon.Etat.NON_RAMASSER));
		}

		placerCochon(new Cochon(7, Cochon.Couleur.GRIS,
				Cochon.Etat.NON_RAMASSER));

		updateCochonStringList();
	}

	/**
	 * Méthode permettant de placer au hasard un cochon sur une grille de 25
	 * cases ( tableau à 2 dimensions )
	 * 
	 * @param c
	 *            le cochon à placer
	 */
	public void placerCochon(Cochon c) {
		int positionX, positionY;
		do {// Tant que la place est occupée (Il y aura toujours de la place
			// libre)
			positionX = Util.unEntierAuHasardEntre1EtY(5) - 1;
			positionY = Util.unEntierAuHasardEntre1EtY(5) - 1;
		} while (tableauDesCochons[positionX][positionY] != null);
		tableauDesCochons[positionX][positionY] = c;
		c.setX(positionX);
		c.setY(positionY);
	}

	/**
	 * Méthode permettant d'ajouter un purin au fermier (Un fermier ne peut
	 * avoir plus de 5 purins)
	 * 
	 * @param partieFermier
	 *            Partie du fermier auquel on doit ajouter un purin
	 */
	void ajouterPurin(PartieFermier partieFermier) {
		int purins = partieFermier.getPurins();
		if (purins == 5) {
			return;
		}
		partieFermier.ajouterPurin();
	}

	/**
	 * Méthode permettant de supprimer un purin à un fermier (Si le fermier perd
	 * son dernier purin il devient observateur)
	 * 
	 * @param partieFermier
	 *            Partie du fermier auquel on doit supprimer un purin
	 */
	void supprimerPurin(PartieFermier partieFermier) {
		partieFermier.supprimerPurin();
		if (partieFermier.getPurins() == 0) {
			partieFermier.getFermier().setStatusJeu(
					Fermier.STATUS_JEU.OBSERVATEUR);
		}
	}

	private void ajoutDeListe(Couleur couleur) {
		for (int i = 0; i < 3; i++) {
			listeDes.add(new DeValeur(couleur));
		}
	}

	/**
	 * méthode qui permet d'ajouter un fermier à la partie courante
	 * 
	 * @param fermier
	 *            fermier à ajouter
	 * @return true si le fermier est ajouté, false sinon
	 */
	public boolean ajouterFermier(PartieFermier fermier) {
		return etat.ajouterFermier(fermier, this);
	}

	/**
	 * méthode qui permet de commencer la partie
	 * 
	 * @return true si la partie est créée , false sinon
	 */
	public boolean commencerPartie() {
		return etat.commencerPartie(this);
	}

	/**
	 * méthode qui permet de commencer le tour suivant
	 * 
	 * @return true si le tour suivant a pu être commencé, false sinon
	 */
	public boolean commencerTourSuivant() {
		return etat.commencerTourSuivant(this);
	}

	/**
	 * méthode qui permet de terminer la partie
	 * 
	 * @return true si la partie a pu être terminée, false sinon
	 */
	public boolean terminerPartie() {
		return etat.terminerPartie(this);
	}

	/**
	 * méthode qui permet d'annuler une partie
	 * 
	 * @return true si la partie a pu être annulée, false sinon
	 * @param partie
	 *            partie à annuler
	 */
	public boolean annulerPartie(Partie partie) {
		return etat.annuler(partie);
	}

	/**
	 * méthode qui permet de renvoyer le gagnant de la partie
	 * 
	 * @return le gagnant s'il y en a un, si non renvoie null
	 * 
	 */
	public Fermier getVainqueur() {
		return (etat.estVainqueur(this) == null ? null : etat
				.estVainqueur(this).getFermier());
	}

	/**
	 * Méthode qui initialise les dés pour un tour (et complète le journal de la
	 * partie)
	 */
	private void nouveauLancer() {
		deOrdre = new DeOrdre();
		this.listeDes = new ArrayList<De>();
		ajoutDeListe(Couleur.VERT);
		ajoutDeListe(Couleur.BLANC);
		ajoutDeListe(Couleur.ROUGE);

		// Lancé du dé ordre
		deOrdre.lancerUnDe();
		// Inscription du lancé du dé ordre dans le journal de la partie
		String resultDeOdre = deOrdre.convertirValeur();
		fichier = new GestionFichierImpl(this.getId());
		fichier.inscrireUneLigne("Les dés sont lancés : le dé Ordre indique << "
				+ resultDeOdre + " >>");

		// Préparation de l'inscription des lancés des dés de couleurs
		String resultRouges = "Les dés rouges sont";
		String resultBlancs = "Les dés blancs sont";
		String resultVerts = "Les dés verts sont";

		// Lancé des dés de couleurs
		for (De d : listeDes) {
			d.lancerUnDe();
			if (((DeValeur) d).getCouleur() == Couleur.ROUGE) {
				resultRouges += " " + d.getValeur() + ",";
			}
			if (((DeValeur) d).getCouleur() == Couleur.BLANC) {
				resultBlancs += " " + d.getValeur() + ",";
			}
			if (((DeValeur) d).getCouleur() == Couleur.VERT) {
				resultVerts += " " + d.getValeur() + ",";
			}
		}
		// Inscription du lancé du dé ordre dans le journal de la partie
		updateDeStringList();
		resultRouges
				.substring(resultRouges.length() - 1, resultRouges.length());
		resultBlancs
				.substring(resultBlancs.length() - 1, resultBlancs.length());
		resultVerts.substring(resultVerts.length() - 1, resultVerts.length());

		fichier.inscrireUneLigne(resultRouges);
		fichier.inscrireUneLigne(resultBlancs);
		fichier.inscrireUneLigne(resultVerts);

	}

	/**
	 * Méthode qui permet à un fermier de prendre un cochon
	 * 
	 * @param cochon
	 *            Cochon à ramaser
	 * @param fermier
	 *            Fermier qui ramasse le cochon
	 * @return True si le cochon a été ramassé, false sinon
	 */
	public boolean prendreUnCochon(Cochon cochon, PartieFermier fermier) {
		// Si fermier est observateur
		if (fermier.getFermier().getStatutJeu() == Fermier.STATUS_JEU.OBSERVATEUR)
			return false;
		// Test si le cochon passé est null dans le cas ou il serait déjà pris
		if (cochon == null)
			return false;
		// Test si le joueur n'a pas déjà pris un cochon
		if (fermier.getFermier().getCochon() != null)
			return false;
		// Test si Cochon déjà ramassé
		if (cochon.getEtat() == Cochon.Etat.RAMASSER)
			return false;

		fermier.getFermier().setCochon(cochon);
		fichier = new GestionFichierImpl(this.getId());
		if (fichier != null)
			fichier.inscrireUneLigne("" + fermier.getFermier().getNom()
					+ " prend un cochon " + cochon.getCouleurName().toString());
		cochon.setEtat(Cochon.Etat.RAMASSER);
		updateCochonStringList();
		return true;
	}

	/**
	 * Enleve un purin à chaque joueur qui n'a pas de cochon de la bonne couleur
	 * et retirer les cochons aux joueurs qui en ont
	 */
	public void enleverPurinsCochons() {
		for (PartieFermier pf : this.getFermiers()) {
			if (pf.getFermier().getCochon() == null
					|| !pf.getFermier().getCochon()
							.compareCouleur(couleurAChoisir)) {
				pf.supprimerPurin();
			}
			if (pf.getFermier().getCochon() != null) {
				pf.getFermier().getCochon().setEtat(Cochon.Etat.NON_RAMASSER);
				pf.getFermier().setCochon(null);
			}
		}
	}

	public boolean finDePartie() {
		return this.etat.terminerPartie(this);
	}

	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + id;
		return result;
	}

	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Partie other = (Partie) obj;
		if (id != other.id)
			return false;
		return true;
	}
}
